import socket
import threading
import pprint
import os
import sys

import web_application


class HttpServerEasy:
    def __init__(self, port, static_path, print_log: bool = False):
        """
        初始化服务器端口和静态文件路径
        :param port: 端口号
        :param static_path: 文件路径
        """
        self.port = port
        self.static_path = static_path
        self.print_log = print_log

    def parse_content(self, content: str) -> dict:
        """
        将请求报文解析成字典
        env["request_line"] = {"method":"None", "path":"None"}
        env["request_header"] = {"Host:www.xxx.com, Connection:Keep-alive"}
        env["request_body"] = {"username":"sundy"}
        :param content:原始报文
        :return:env 一个字典
        """
        # 用 \r\n\r\n 分成两个大的部分
        header = content.split("\r\n\r\n")[0]
        body = content.split("\r\n\r\n")[1]
        env = dict()

        # 请求行部分
        env["request_line"] = {"method": header.split("\r\n")[0].split(" ")[0],
                               "path": header.split("\r\n")[0].split(" ")[1]}

        # 请求头部分
        env["request_header"] = \
            {x.split(":")[0]: x.split(":")[1] for x in header.split("\r\n")[1:]}

        # 请求体部分
        try:
            env["request_body"] = \
                {x.split("=")[0]: x.split("=")[1] for x in body.split("&")}
            return env
        except IndexError as e:
            env["request_body"] = None
            return env

    def handle_con(self, con, addr):
        """
        处理收发数据请求
        :param con: 处理数据收发的套接字
        :param addr: 地址
        """
        if self.print_log:
            print("开始处理来自{}的请求".format(addr))

        # 接收来自客户端的http请求数据
        request_data = con.recv(2048).decode("utf-8")
        # print(request_data[0:40])

        # 如果请求数据为0 关闭套接字
        if len(request_data) == 0:
            print("关闭连接{}".format(addr))
            con.close()
            return

        response_paramer = [
            "HTTP/1.0 200 OK".encode("utf-8"),
            "Content-Type: text/html; charset=utf-8 \r\n".encode("utf-8"),
            # "Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l ".encode(
            #     "utf-8"),
            # "Set-Cookie: token=QWxhZGRpbjpPcGVuU2VzYW1l ".encode("utf-8"),
        ]

        # 解析出用户想访问的页面名字
        env = self.parse_content(request_data)
        request_page = env["request_line"]["path"]

        if self.print_log:
            pprint.pprint(env)

        try:
            if not request_page.endswith("html"):
                # 处理动态请求
                response = web_application.application(env)
                if "Set-Cookies" in response:
                    # 在请求报文中添加Set-Cookies
                    set_cookies = "Set-Cookie:{}".format(
                        response["Set-Cookies"])
                    response_paramer.insert(1, set_cookies.encode("utf-8"))
                response_paramer.append(response["body"].encode("utf-8"))
                response = b"\r\n".join(response_paramer)
                con.send(response)
            #  发送用户需要的页面
            else:
                with open(self.static_path + request_page, mode="rb") as file:
                    response_paramer.append(file.read())
                    response = b"\r\n".join(response_paramer)
                    con.send(response)
        except Exception as e:
            # 如果用户访问的页面不存在，返回404
            response_paramer[0] = "HTTP/1.0 404 Not Found".encode("utf-8")
            response_paramer.append("你输入的啥？ 我都找不到~~~".encode("utf-8"))
            response = b"\r\n".join(response_paramer)
            con.send(response)

        con.close()

    def start_server(self) -> None:
        """
        启动服务器
        :return: None
        """
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            # 设置端口复用
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            sock.bind(("localhost", self.port))
            sock.listen(5)
            if self.print_log:
                print("localhost:{}  开始监听请求.... http://localhost:{}".format(
                    self.port, self.port))
            while True:
                con, addr = sock.accept()
                th_handle = threading.Thread(target=self.handle_con,
                                             kwargs={"con": con, "addr": addr},
                                             daemon=True)
                th_handle.start()


if __name__ == '__main__':
    try:
        port = int(sys.argv[1])
    except IndexError as e:
        print("命令形如 python web_server 8080 \n {}".format(e))
    except ValueError as e:
        print("命令形如 python web_server 8080 \n {}".format(e))
    else:
        http_server = HttpServerEasy(port, "static", print_log=True)
        http_server.start_server()
